﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Input;

namespace PonGun
{
    public class Ball : Base2DObject
    {
        float _speed { get; set; }
        public float Speed { get { return _speed; } set { _speed = value; Velocity = Vector2.Clamp(Velocity * _speed, -(Vector2.One * _speed), Vector2.One * _speed); } }

        public Ball(Game1 game, string asset = "Textures/White")
            : base(game)
        {
            Width = 4;
            Height = 4;

            Asset = "Textures/White";

            Speed = 1;
            Friction = 0;

            RegisteredCollider = true;
        }

        public void KillBall()
        {
            RegisteredCollider = false;
            collisionManager.UnRegister(this, false);            
        }

        public override void Collided(CollisionData collisionData)
        {
            base.Collided(collisionData);

            Base2DObject collidedWith = null;
            if (collisionData.Objects[0] == this)
                collidedWith = (Base2DObject)collisionData.Objects[1];
            else
                collidedWith = (Base2DObject)collisionData.Objects[0];

            if (collidedWith is Pickup)
            {
                Game.Content.Load<SoundEffect>("Audio/SFX/bhpu").Play();

                Pickup pickUp = (Pickup)collidedWith;

                if (pickUp.PickedUp)
                    return;
                
                pickUp.PickedUp = true;
                
                int bcnt = 0;
                switch (pickUp.PickupTyp)
                {
                    case PickupType.MultiBall:
                        Game.MultiBall();
                        Game.ShowPopUpMessage(new PopMsg() { message = "Multi Ball", Color = pickUp.Color, position = pickUp.Position });
                        break;
                    case PickupType.MinusBall:
                        Game.RemoveBall(this);
                        Game.ShowPopUpMessage(new PopMsg() { message = "Ball Loss", Color = pickUp.Color, position = pickUp.Position });
                        break;
                    case PickupType.Nova:
                        // Nova ball
                        // Get back to a single ball
                        Game.ClearExcessBalls();
                        
                        if (!Game.RenderNova)
                            Game.RenderNova = true;
                        else
                            Game.RenderNova = false;

                        Game.ShowPopUpMessage(new PopMsg() { message = "NOVA!!", Color = pickUp.Color, position = pickUp.Position });
                        break;
                    case PickupType.FlipH:
                        if (Game1.ScreenSpriteEffect != SpriteEffects.FlipHorizontally)
                            Game1.ScreenSpriteEffect = SpriteEffects.FlipHorizontally;
                        else
                            Game1.ScreenSpriteEffect = SpriteEffects.None;

                        Game.ShowPopUpMessage(new PopMsg() { message = "Flip Horizontally", Color = pickUp.Color, position = pickUp.Position });
                        break;
                    case PickupType.FlipV:
                        if (Game1.ScreenSpriteEffect != SpriteEffects.FlipVertically)
                            Game1.ScreenSpriteEffect = SpriteEffects.FlipVertically;
                        else
                            Game1.ScreenSpriteEffect = SpriteEffects.None;
                        Game.ShowPopUpMessage(new PopMsg() { message = "Flip Vertically", Color = pickUp.Color, position = pickUp.Position });
                        break;
                    case PickupType.ScreenSpin:
                        if (!Game1.ScreenRotating)
                            Game1.ScreenRotating = true;
                        Game.ShowPopUpMessage(new PopMsg() { message = "Spin Screen", Color = pickUp.Color, position = pickUp.Position });
                        break;
                    case PickupType.Mist:
                        if (!Game.RenderMist)
                            Game.RenderMist = true;
                        Game.ShowPopUpMessage(new PopMsg() { message = "Mitsy mist...", Color = pickUp.Color, position = pickUp.Position });
                        break;
                    case PickupType.LevelUp:
                        Game.Level += 1;
                        Game.ShowPopUpMessage(new PopMsg() { message = "Level UP!", Color = pickUp.Color, position = pickUp.Position });
                        break;
                }

                ParticleStrikeEffect(Game1.leftNormal, pickUp.Color);
                ParticleStrikeEffect(Game1.rightNormal, pickUp.Color);
                ParticleStrikeEffect(Game1.topNormal, pickUp.Color);
                ParticleStrikeEffect(Game1.botNormal, pickUp.Color);
            }

            Vector2 n = collidedWith.GetCollisionNormal(this);

            if (collidedWith is Bat)
            {
                if (collidedWith.GetContactPosition(this) != -Vector2.One) // So not passing through the bat..
                {
                    Game.Content.Load<SoundEffect>("Audio/SFX/bhbt").Play();
                    Velocity = Vector2.Clamp(Vector2.Reflect(Velocity, n), -(Vector2.One * Speed), Vector2.One * Speed);
                    ParticleStrikeEffect(n, ((Bat)collidedWith).Color);
                }

            }

            if (collidedWith is Ball)
            {
                Game.Content.Load<SoundEffect>("Audio/SFX/bhbl").Play();
                Velocity = Vector2.Clamp(Vector2.Reflect(Velocity, n), -(Vector2.One * Speed), Vector2.One * Speed);
                ParticleStrikeEffect(n, Color);
            }

            if (collidedWith is City)
            {
                if (((City)collidedWith).CityBallDamage(this))
                {
                    Game.Content.Load<SoundEffect>("Audio/SFX/bhcy").Play();
                    
                    Velocity = Vector2.Clamp(Vector2.Reflect(Velocity, collidedWith.GetCollisionNormal(this)), -(Vector2.One * Speed), Vector2.One * Speed);
                    ParticleStrikeEffect(n, ((City)collidedWith).Color);
                }
            }

            if (collidedWith is Block)
            {
                if (((Block)collidedWith).Erroded(this, true))
                {
                    Game.Content.Load<SoundEffect>("Audio/SFX/bhbk").Play();
                    Velocity = Vector2.Clamp(Vector2.Reflect(Velocity, n), -(Vector2.One * Speed), Vector2.One * Speed);
                    ParticleStrikeEffect(n, ((Block)collidedWith).Color);
                }
            }

            if (collidedWith is Bullet)
            {
                Game.Content.Load<SoundEffect>("Audio/SFX/bhblt").Play();
                if ((Velocity.X < 0 && collidedWith.Velocity.X > 0) || (Velocity.X > 0 && collidedWith.Velocity.X < 0))
                {
                    Position -= Velocity;
                    Velocity = Vector2.Reflect(Velocity, Game1.rightNormal);
                    ParticleStrikeEffect(Game1.rightNormal, Color);
                }
                else
                    Position += collidedWith.Velocity;
            }
        }

        public void SetInitialVelocity(float speed)
        {
            bool left = Game1.rnd.Next(0, 2) == 0;
            bool up = Game1.rnd.Next(0, 2) == 0;

            Velocity = new Vector2(left ? -1 : 1, up ? -1 : 1) * Speed;
        }

        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);

            if (Position.Y <= minPosition.Y)
            {
                Game.Content.Load<SoundEffect>("Audio/SFX/bhbt").Play();
                Velocity = Vector2.Reflect(Velocity, Game1.topNormal);
                ParticleStrikeEffect(Game1.topNormal, Color);
            }

            if (Position.Y >= maxPosition.Y)
            {
                Game.Content.Load<SoundEffect>("Audio/SFX/bhbt").Play();
                Velocity = Vector2.Reflect(Velocity, Game1.botNormal);
                ParticleStrikeEffect(Game1.botNormal, Color);
            }

            // For test
            if (Position.X <= minPosition.X)
            {
                Game.Bats[1].WallHit();
                Game.Content.Load<SoundEffect>("Audio/SFX/bhbt").Play();
                Velocity = Vector2.Reflect(Velocity, Game1.leftNormal);
                ParticleStrikeEffect(Game1.leftNormal, Color);
            }

            if (Position.X >= maxPosition.X)
            {
                Game.Content.Load<SoundEffect>("Audio/SFX/bhbt").Play();
                Game.Bats[0].WallHit();
                Velocity = Vector2.Reflect(Velocity, Game1.rightNormal);
                ParticleStrikeEffect(Game1.rightNormal, Color);
            }

            Position = Vector2.Clamp(Position, minPosition, maxPosition);
        }

        public void ParticleStrikeEffect(Vector2 normal, Color color)
        {
            Vector2 orgNorm = normal;
            TimeSpan lifetime = new TimeSpan(0, 0, 0, 0, 100);
            float fadeSpeed = .1f;
            
            Vector2 velMul = Vector2.One * MathHelper.Lerp(4, 8, (float)Game1.rnd.NextDouble());
            Game.testEmitter.AddParticle(new Particle(Game) { Position = Position, Velocity = normal * velMul, Spin = -.1f, LifeSpan = lifetime, FadeSpeed = fadeSpeed, Color = color });

            if (orgNorm.X == 0)
                normal.X -= .25f;
            
            if (orgNorm.Y == 0)
                normal.Y -= .25f;

            velMul = Vector2.One * MathHelper.Lerp(4, 8, (float)Game1.rnd.NextDouble());
            Game.testEmitter.AddParticle(new Particle(Game) { Position = Position, Velocity = normal * velMul, Spin = -.1f, LifeSpan = lifetime, FadeSpeed = fadeSpeed, Color = color });

            if (orgNorm.X == 0)
                normal.X -= .25f;

            if (orgNorm.Y == 0)
                normal.Y -= .25f;

            velMul = Vector2.One * MathHelper.Lerp(4, 8, (float)Game1.rnd.NextDouble());
            Game.testEmitter.AddParticle(new Particle(Game) { Position = Position, Velocity = normal * velMul, Spin = -.1f, LifeSpan = lifetime, FadeSpeed = fadeSpeed, Color = color });

            if (orgNorm.X == 0)
                normal.X += 1.25f;

            if (orgNorm.Y == 0)
                normal.Y += 1.25f;

            velMul = Vector2.One * MathHelper.Lerp(4, 8, (float)Game1.rnd.NextDouble());
            Game.testEmitter.AddParticle(new Particle(Game) { Position = Position, Velocity = normal * velMul, Spin = -.1f, LifeSpan = lifetime, FadeSpeed = fadeSpeed, Color = color });

            if (orgNorm.X == 0)
                normal.X += .25f;

            if (orgNorm.Y == 0)
                normal.Y += .25f;

            velMul = Vector2.One * MathHelper.Lerp(4, 8, (float)Game1.rnd.NextDouble());
            Game.testEmitter.AddParticle(new Particle(Game) { Position = Position, Velocity = normal * velMul, Spin = -.1f, LifeSpan = lifetime, FadeSpeed = fadeSpeed, Color = color });
        }
    }
}
